
from io import SEEK_CUR, SEEK_SET
from xml.sax.handler import ContentHandler
from xml.sax import SAXParseException, make_parser 
import click

class MyContentHandler(ContentHandler):

    def startElement(self, name, attrs):
        self.elementName = name
        self.elementAttrs = attrs
        self.isElementStart = True
        self.elementConent = ""

    def endElement(self, name):
        self.elementName = name
        self.isElementStart = False
        
    def characters(self, content):
        if content != None:
            self.elementConent = content

def printElement(elementName,isStartElement,elementAttris,elementContent):
    print("[<",end="")
    if not isStartElement:
        print("/",end="")
    print(elementName,end="")
    if(elementAttris != None):
        for key,value in elementAttris.items():
            print(" "+key+"="+value,end=" ")
    print(">",end="")
    if(elementContent != None):
        print(elementContent,end="")
    print("]")

def charSeek(file,offset,maxOffsetLength):
    maxBuf = 1024
    if maxBuf > offset:
        maxBuf = offset
    
    pos = 0
    line = ""
    while pos < offset:
        if (pos + maxBuf) > offset:
            maxBuf = offset - pos
        line = file.readline(maxBuf)
        pos = pos + maxBuf
    return line[-maxOffsetLength:]

def readFileLineColumnContext(fileName,lineNumber,columnNumber,maxOffsetLength):
    # print("[File:%s]-[Line:%d]-[Column:%d]-[MaxOffsetLength:%d]" 
    #     % (fileName,lineNumber,columnNumber,maxOffsetLength))

    with open(fileName,encoding="utf-8") as f:
        n = 1
        maxBuf = 1024
        line = ""
        while n < lineNumber:
            n = n +1
            lineEnd = False
            while not lineEnd:
                line = f.readline(maxBuf)
                # print(line)
                a = line[-1:]
                if a == "\n":
                    lineEnd = True
                    break
        
        # f.seek是针对字节的,不要使用,不然如果位置在一个多字节字符的中间,read解码utf-8字符会报错.
        preLine = charSeek(f,columnNumber,maxOffsetLength)
        b1 = f.read(maxOffsetLength)
        print("-->前一行:"+line[-maxOffsetLength:],end="")
        print("-->当前行:" +preLine+b1)

    pass

@click.command(help="""校验XML格式完整性,请使用--help查看帮助\n
    XmlValidator --path XML路径""")
@click.option('--path',default="",help="XML文件路径") 
@click.pass_context 
def parseFile(ctx,path):
    
    if(len(path) == 0):
        print("请输入有效XML路径!")
        return

    parser = make_parser()
    handler1 = MyContentHandler()
    parser.setContentHandler(handler1)
    
    try:
        parser.parse(path)
    except SAXParseException as e:
        print("-->解析错误: ["+str(e)+"]")
        print("-->解析起始元素上下文-1: ",end="")
        printElement(handler1.elementName,handler1.isElementStart,
            handler1.elementAttrs,handler1.elementConent)
        readFileLineColumnContext(path,e.getLineNumber(),e.getColumnNumber(),20)
        
def test():
    return

if __name__ == "__main__":
    print("Begin Parse!")
    parseFile(obj={})  
    print("End Parse!")
    pass